package com.ydl.iec.demo;

import com.ydl.iec.iec104.common.BasicInstruction104;
import com.ydl.iec.iec104.enums.QualifiersEnum;
import com.ydl.iec.iec104.enums.TypeIdentifierEnum;
import com.ydl.iec.iec104.message.MessageDetail;
import com.ydl.iec.iec104.message.MessageInfo;
import com.ydl.iec.iec104.server.handler.ChannelHandler;
import com.ydl.iec.iec104.server.handler.DataHandler;
import com.ydl.iec.util.ByteUtil;
import com.ydl.iec.util.Iec104Util;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@Slf4j
public class SysDataHandler implements DataHandler {

    @Getter
    ChannelHandler ctx;

    public SysDataHandler(){

    }

    @Override
    public void handlerAdded(ChannelHandler ctx) throws Exception {
        // 连接成功后
        this.ctx = ctx;
        log.info("连接成功");
    }

    @Override
    public void channelRead(ChannelHandler ctx, MessageDetail ruleDetail104) throws Exception {
        //todo Dong 修改指令处理逻辑
        // 收到消息后
        TypeIdentifierEnum typeIdentifierEnum = ruleDetail104.getTypeIdentifier();
        int type = typeIdentifierEnum.getValue() & 0xff;
//        log.info("接收到的指令.0x{}",Integer.toHexString(type));
//        ControlManageUtil cmu = Iec104ThreadLocal.getControlPool();
        short accept = 0;
        short transport = 0;
        switch (type){
            case 0x64:
                ctx.writeAndFlush(BasicInstruction104.getYesGeneralCallRuleDetail104());
                GeneralCallString.setTotalCall(ctx);
                ctx.writeAndFlush(BasicInstruction104.getEndGeneralCallRuleDetail104());
                break;
            case 0x2d:  //场景5：遥控单点资源开停机
                singleRemoteControl(ctx,ruleDetail104);
                break;
            case 0x89:  //接收到计划曲线
                acceptPlanCurve(ctx,ruleDetail104);
                break;
            default:
                log.info("接收到不可处理类型.0x{}",Integer.toHexString(type));
        }
        // 注意 往ctx.writeAndFlush中存放的应该是自己封装的 MessageDetail对象
//        ctx.writeAndFlush(BasicInstruction104.getEndGeneralCallRuleDetail104());
    }

    private void acceptPlanCurve(ChannelHandler ctx, MessageDetail ruleDetail104) {
        int address = ruleDetail104.getMessageAddress();
        int index = Test.resourceManage.getAccepted();
        if(address == 26369){ //从第一个点发起
            index = 0;
        }
        List<MessageInfo> messages = ruleDetail104.getMessages();
        for (MessageInfo message : messages) {
            byte[] messageInfos = message.getMessageInfos();
            float f = ByteUtil.littleEndianByteArrayToFloat(messageInfos);
            Test.resourceManage.getPlanCurve()[index++] = f;
        }
        Test.resourceManage.setAccepted(index);
        //接收完毕，原包返回
        ruleDetail104.setTransferReason(Iec104Util.getTransferReasonShort(false, true, (short)7));
        ctx.writeAndFlush(ruleDetail104);
        //拆分计划曲线
        if(Test.resourceManage.getAccepted()==288){
            log.info("计划曲线接收完毕="+Test.resourceManage.getPlanCurve());
            Test.timer.cancel();
            boolean b = Test.resourceManage.splitPlanCurve();
            Test.timer = new Timer();
            if(b)Test.resourceManage.startProcess();
        }
    }

    private void singleRemoteControl(ChannelHandler ctx,MessageDetail message){
        short res = message.getTransferReason();
        List<MessageInfo> lstMessage = message.getMessages();
        switch (res){
            case 6: //下行激活
                short txReason = 7;//激活确认
                processSwitchOther(ctx,lstMessage,txReason);
                break;
            case 8: //停止激活
                txReason = 9;//停止激活确认
                processSwitchOther(ctx,lstMessage,txReason);

                txReason = 10;//激活终止
                processSwitchOther(ctx,lstMessage,txReason);
                break;
            default:
                log.info("下行原因不明:{}",res);
                break;
        }
    }



    private void processSwitchOther(ChannelHandler ctx,List<MessageInfo> lstSource,short txReason){
        for(MessageInfo mi : lstSource){
            int address = mi.getMessageAddress();
            byte[] data = mi.getMessageInfos();
            int first = data[0]>>7&1; //0.遥控执行命令  1.遥控选择命令
            int last = data[0] & 1; // 0 开 , 1 合
            boolean idError = true;
            Point point = Test.resourceManage.getAllPoints().get(address);
            if(point!=null){
                MessageDetail response = getMessage(address,txReason,data);
                ctx.writeAndFlush(response);
                if(first==0){
                    point.setValue(last);
                    Test.viewPanel.updateView(point);
                }
                idError = false;
            }

            if(idError){
                MessageDetail response = getMessage(address,(short)10,data);
                ctx.writeAndFlush(response);
                log.info("资源状态点号不正确:{}",address);
            }
        }
    }

    private MessageDetail getMessage(int sourceId,short transferReason,byte[] op){
        TypeIdentifierEnum typeIdentifierEnum = TypeIdentifierEnum.onePointTelecontrol;
        int sq = 0;
        boolean isContinuous = sq == 0 ? false : true;
//        short accept = Test.RxCounter;
//        short send = Test.TxCounter;
//        byte[] control = Iec104Util.getIcontrol(accept, send);
//        short transferReason = 7;
        // true：1 ; false ： 0
        byte[] control = {0,0,0,0};
        boolean isTest = false;
        // true:0 false;1
        boolean isPN = true;

        // 消息地址 总召唤地址为0
        int messageAddress = 0;

        QualifiersEnum qualifiers = QualifiersEnum.getQualifiersEnum(TypeIdentifierEnum.onePointTelecontrol,(byte)1);
        List<MessageInfo> messages = new ArrayList<>();
        MessageInfo message = new MessageInfo();
//		message.setQualifiersType(qualifiers);
        message.setMessageAddress(sourceId);
//        byte[] info = {op};
        message.setMessageInfos(op);

        messages.add(message);
        MessageDetail ruleDetail104 = new MessageDetail(control, typeIdentifierEnum, isContinuous, isTest, isPN, transferReason,
                (short)0, messageAddress, messages, null, qualifiers);
        return ruleDetail104;
    }

    public void sendYx(Point point) {
        TypeIdentifierEnum typeIdentifierEnum = TypeIdentifierEnum.onePointTeleindication;
        boolean isContinuous = false;
        byte[] control = new byte[4];
        boolean isTest = false;
        boolean isPN = true;
        short transferReason = 3 ;
        // 消息地址 总召唤地址为0
        int messageAddress = point.getPointId();
        short terminalAddress = Short.parseShort(Test.config.getProperty("terminal.id"));;
        QualifiersEnum qualifiers = QualifiersEnum.getQualifiersEnum(TypeIdentifierEnum.onePointTeleindication,(byte)1);
        List<MessageInfo> messages = new ArrayList<>();
        MessageInfo message = new MessageInfo();
        message.setMessageAddress(point.getPointId());
        byte x = (byte)((int)point.getValue());
        byte[] info = {x};
        message.setMessageInfos(info);
        messages.add(message);
        MessageDetail ruleDetail104 = new MessageDetail(control, typeIdentifierEnum, isContinuous, isTest, isPN, transferReason,
                terminalAddress, messageAddress, messages, new Date(), qualifiers);
        ctx.writeAndFlush(ruleDetail104);
    }

    public void sendWarn() {
        TypeIdentifierEnum typeIdentifierEnum = TypeIdentifierEnum.onePointTeleindication;
        boolean isContinuous = false;
        byte[] control = new byte[4];
        boolean isTest = false;
        boolean isPN = true;
        short transferReason = 3 ;
        // 消息地址 总召唤地址为0
        int messageAddress = 0;
        short terminalAddress = Short.parseShort(Test.config.getProperty("terminal.id"));;
        QualifiersEnum qualifiers = QualifiersEnum.getQualifiersEnum(TypeIdentifierEnum.onePointTeleindication,(byte)1);
        List<MessageInfo> messages = new ArrayList<>();
        MessageInfo message = new MessageInfo();
        message.setMessageAddress(24577);
        byte x = (byte)(1);
        byte[] info = {x};
        message.setMessageInfos(info);
        messages.add(message);
        MessageDetail ruleDetail104 = new MessageDetail(control, typeIdentifierEnum, isContinuous, isTest, isPN, transferReason,
                terminalAddress, messageAddress, messages, new Date(), qualifiers);
        ctx.writeAndFlush(ruleDetail104);
    }

    public void sendYc(List<Point> points) {
        if(ctx==null)return;
        TypeIdentifierEnum typeIdentifierEnum = TypeIdentifierEnum.shortFloatingPointTelemetry;
        boolean isContinuous = false;
        byte[] control = new byte[4];
        boolean isTest = false;
        boolean isPN = true;
        short transferReason = 3 ;
        // 消息地址 总召唤地址为0
        int messageAddress = 0;
        short terminalAddress = Short.parseShort(Test.config.getProperty("terminal.id"));;
        QualifiersEnum qualifiers = QualifiersEnum.qualityQualifiers;
        List<MessageInfo> messages = new ArrayList<>();
        for (Point point : points) {
            MessageInfo message = new MessageInfo();
            message.setMessageAddress(point.getPointId());
            message.setQualifiersType(qualifiers);
            byte[] info = ByteUtil.floatToBytes(point.getValue());
            message.setMessageInfos(info);
            messages.add(message);
        }
        MessageDetail ruleDetail104 = new MessageDetail(control, typeIdentifierEnum, isContinuous, isTest, isPN, transferReason,
                terminalAddress, messageAddress, messages, new Date(), qualifiers);
        ctx.writeAndFlush(ruleDetail104);
    }
}
